
#include "stdafx.h"

/************************************************************************/
/* TaskQueM.h
/* 
/* Sample code for `Multithreading Applications in Win32'
/* 
/* Call ThreadFunc NUM_TASKS times, using no more than THREAD_POOL_SIZE 
/* threads. This version uses WaitForMultipleObjects
/* to provide a more optimal solution.
/* 
/* Build command: cl /MD TaskQueM.c
/************************************************************************/

#define WIN32_LEAN_AND_MEAN

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <time.h>
#include <conio.h>
#include "MtVerify.h"

DWORD WINAPI ThreadFunc(LPVOID);

#define THREAD_POOL_SIZE 3
#define MAX_THREAD_INDEX THREAD_POOL_SIZE-1
#define NUM_TASKS 6

int main(int argc, char* argv[])
{


	HANDLE hThrds[THREAD_POOL_SIZE];
	int slot = 0;
	DWORD threadId;
	int i;
	DWORD rc;

	for (i=1; i<=NUM_TASKS; i++)
	{
		/* 
		* Until we're used all threads in 
		* the pool, do not need to wait
		* for one to exit
		*/
		if (i>THREAD_POOL_SIZE)
		{
			// wait for one thread to terminate
			rc = WaitForMultipleObjects(
				THREAD_POOL_SIZE,
				hThrds,
				FALSE,
				INFINITE);

			slot = rc - WAIT_OBJECT_0;

			MTVERIFY(slot >= 0
				&& slot < THREAD_POOL_SIZE);

			printf("Slot %d terminated\n", slot);
			MTVERIFY(CloseHandle(hThrds[slot]));
		}

		// create a new thread in the given
		// available slot
		MTVERIFY( hThrds[slot++] = CreateThread(NULL,
			0,
			ThreadFunc,
			(LPVOID)&slot,
			0,
			&threadId));
		printf("Launched thread #%d (slot %d)\n", i, slot);
	}

	// now wait for all threads to terminate
	rc = WaitForMultipleObjects(
		THREAD_POOL_SIZE,
		hThrds,
		TRUE,
		INFINITE);
	MTVERIFY( rc >= WAIT_OBJECT_0
		&& rc < WAIT_OBJECT_0+THREAD_POOL_SIZE);
	for (slot=0; slot<THREAD_POOL_SIZE; slot++)
		MTVERIFY(CloseHandle(hThrds[slot]));
	printf("All slots terminated\n");

	getch();

	return EXIT_SUCCESS;
}

/*
* This function just calls sleep for a random amount of time, 
* thereby simulating some task that takes time.
*
* the param `n' is the index into the handle array, kept for
* informational purposes
*/
DWORD WINAPI ThreadFunc(LPVOID n)
{
	DWORD* slot = reinterpret_cast<DWORD*>(n);
	srand(GetTickCount());

	Sleep((rand()%8)*500+500);
	printf("Slot %d idle\n", *slot);
	return (*slot);
}